// RedJey Graphics User Interface Library for J2ME Platform.
// Copyright (C) 2008 Yevgen Krapiva
//
// This library is free software; you can redistribute
// it and/or modify it under the terms of the
// GNU Lesser General Public License as published
// by the Free Software Foundation; either version 3.0
// of the License, or any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

package com.incrediblesoft.redjey;

/**
 * @author Yevgen Krapiva<br>
 *         Homepage: http://code.google.com/p/redjey/<br>
 *         Feedback: ykrapiva@gmail.com<br>
 *         Copyright (C) 2008 Yevgen Krapiva<br>
 */

import com.incrediblesoft.redjey.event.MouseEvent;
import com.incrediblesoft.redjey.event.ActionEvent;
import com.incrediblesoft.redjey.event.ActionListener;

import javax.microedition.lcdui.Graphics;
import java.util.Hashtable;


public class ScrollPane extends Container implements ActionListener
{
    protected Component view;
    protected ScrollBar vScrollBar;
    protected ScrollBar hScrollBar;

    public static final int SCROLLBARS_ALWAYS = 0;
    public static final int SCROLLBARS_AS_NEEDED = 1;
    public static final int SCROLLBARS_NEVER = 2;

    protected int scrollbarDisplayPolicy;

    public ScrollPane(Component view)
    {
        this(view, SCROLLBARS_AS_NEEDED);
    }

     public ScrollPane(Component view, String styleClassName)
    {
        this(view, SCROLLBARS_AS_NEEDED, styleClassName);
    }

    public ScrollPane(Component view, int scrollbarDisplayPolicy)
    {
        this(view, scrollbarDisplayPolicy, null);
    }

    public ScrollPane(Component view, int scrollbarDisplayPolicy, String styleClassName)
    {
        super(styleClassName);

        this.view = view;
        this.view.parent = this;
        this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
        this.vScrollBar = new ScrollBar(ScrollBar.VERTICAL);
        this.vScrollBar.addActionListener(this);
        this.vScrollBar.parent = this;
        this.hScrollBar = new ScrollBar(ScrollBar.HORIZONTAL);
        this.hScrollBar.addActionListener(this);
        this.hScrollBar.parent = this;

        setLayout(null);

        add(vScrollBar);
        add(hScrollBar);
        add(view);
        
        setState(NORMAL);
    }

    public String getName()
    {
        return "ScrollPane";
    }

    protected Dimension calcPreferredSize(int paddingHorizontal, int paddingVertical, CustomFont font, Hashtable attributes)
    {
        Dimension prefSize = view.getPreferredSize();
        if (scrollbarDisplayPolicy != SCROLLBARS_NEVER)
        {
            Dimension vPrefSize = vScrollBar.getPreferredSize();
            Dimension hPrefSize = hScrollBar.getPreferredSize();
            prefSize.width += vPrefSize.width;
            prefSize.height += hPrefSize.height;
        }

        return prefSize;
    }
   /* public Component getComponentAt(int x, int y, boolean deepSearch)
    {
        if (vScrollBar.isVisible())
        {
            if (vScrollBar.getBounds().inside(x, y))
               return deepSearch ? vScrollBar.getComponentAt(x - vScrollBar.x, y - vScrollBar.y, deepSearch) : vScrollBar;
        }
        if (hScrollBar.isVisible())
        {
            if (hScrollBar.getBounds().inside(x, y))
                return deepSearch ? hScrollBar.getComponentAt(x - hScrollBar.x, y - hScrollBar.y, deepSearch) : hScrollBar;
        }

        return super.getComponentAt(x, y, deepSearch);
    } */

   /* protected Dimension calcPreferredSize(int paddingHorizontal, int paddingVertical, CustomFont font, Hashtable attributes)
    {
        Dimension dim = new Dimension(view.getPreferredSize());
        if (scrollbarDisplayPolicy != SCROLLBARS_NEVER)
        {
            dim.width += vScrollBar.getPreferredSize().width + paddingHorizontal;
            dim.height += hScrollBar.getPreferredSize().height + paddingVertical;
        }

        return dim;
    }*/

    public void setState(int index)
    {
        super.setState(index);

        if (vScrollBar != null)
        {
            String style = (String) currentStyle.attributes.get("vertical-scrollbar-class");
            if (style != null) vScrollBar.setStyleClass(style);
        }

        if (hScrollBar != null)
        {
            String style = (String) currentStyle.attributes.get("horizontal-scrollbar-class");
            if (style != null) hScrollBar.setStyleClass(style);
        }
    }

    public void processMouseScrollEvent(MouseEvent event)
    {
        // send event to deepper components
        super.processMouseScrollEvent(event);

        if (!event.isConsumed())
        {
            switch(event.getID())
            {
                case MouseEvent.MOUSE_SCROLL_VERTICAL:
                    int prevValue = vScrollBar.getValue();
                    vScrollBar.setValue(vScrollBar.getValue() + event.getValue());
                    if (prevValue != vScrollBar.getValue())
                    {
                        vScrollBar.fireActionEvent();
                        event.consume();
                    }
                    break;

                case MouseEvent.MOUSE_SCROLL_HORIZONTAL:
                    prevValue = hScrollBar.getValue();
                    hScrollBar.setValue(hScrollBar.getValue() + event.getValue());
                    if (prevValue != hScrollBar.getValue())
                    {
                        hScrollBar.fireActionEvent();
                        event.consume();
                    }
                    break;

                    //default:
                    //  super.processMouseEvent(event);
                    //return;
            }
            //UIManager.setPrevCursorPosition();

        }

    }

    /**
     * Returns the view component
     * @return
     */
    public Component getView()
    {
        return view;
    }

    public void setView(Component view)
    {
        this.view = view;
        invalidate();
    }

    public ScrollBar getHorizontalBar()
    {
        return hScrollBar;
    }

    public ScrollBar getVerticalBar()
    {
        return vScrollBar;
    }

    /*public void tick(int dt)
    {
        vScrollBar.tick(dt);
        hScrollBar.tick(dt);
        super.tick(dt);
    }*/

    protected void validateComponent()
    {
        boolean showVScrollBar = false;
        boolean showHScrollBar = false;

        Dimension viewPrefSize = view.getPreferredSize();

        switch(scrollbarDisplayPolicy)
        {
            case SCROLLBARS_ALWAYS:
                showVScrollBar = true;
                showHScrollBar = true;
                break;

            case SCROLLBARS_NEVER:
                showVScrollBar = false;
                showHScrollBar = false;
                break;

            case SCROLLBARS_AS_NEEDED:
                showHScrollBar = clientSize.width < viewPrefSize.width;
                showVScrollBar = clientSize.height < viewPrefSize.height;
                break;
        }

        vScrollBar.setVisible(showVScrollBar);
        hScrollBar.setVisible(showHScrollBar);
        
        if (showVScrollBar)
        {
            vScrollBar.setSize(vScrollBar.getPreferredSize().width, clientSize.height - (showHScrollBar ? hScrollBar.getPreferredSize().height : 0));
            vScrollBar.setLocation(width - insets[1] - vScrollBar.width, insets[2]);
        }
        if (showHScrollBar)
        {
            hScrollBar.setSize(clientSize.width - (showVScrollBar ? vScrollBar.getPreferredSize().width : 0), hScrollBar.getPreferredSize().height);
            hScrollBar.setLocation(insets[0], height - insets[3] - hScrollBar.height);
        }

        Dimension visibleSpace =  new Dimension(clientSize.width  - (showVScrollBar ? vScrollBar.width - currentStyle.paddingHorizontal : 0),
                                                clientSize.height - (showHScrollBar ? hScrollBar.height - currentStyle.paddingVertical : 0));

        if ((view.getAlignment() & H_EXPAND) > 0 && viewPrefSize.width < visibleSpace.width)
            viewPrefSize.width = visibleSpace.width;
        if ((view.getAlignment() & V_EXPAND) > 0 && viewPrefSize.height < visibleSpace.height)
            viewPrefSize.height = visibleSpace.height;

        view.setSize(viewPrefSize);
        view.setLocation(insets[0], insets[2]);

        hScrollBar.setMaximum(view.getWidth());
        hScrollBar.setVisibleAmount(visibleSpace.width);

        vScrollBar.setMaximum(view.getHeight());
        vScrollBar.setVisibleAmount(visibleSpace.height);
    }

    protected void paintComponent(Graphics g)
    {
        //Current clip rect
        int clipX = g.getClipX();
        int clipY = g.getClipY();
        int clipW = g.getClipWidth();
        int clipH = g.getClipHeight();

        g.clipRect(insets[0], insets[2], clientSize.width  - (vScrollBar != null ? vScrollBar.width - currentStyle.paddingHorizontal : 0),
                   clientSize.height - (hScrollBar != null ? hScrollBar.height - currentStyle.paddingVertical : 0));

        printComponent(g, view);

        g.setClip(clipX, clipY, clipW, clipH);

        if (hScrollBar.isVisible()) printComponent(g, hScrollBar);
        if (vScrollBar.isVisible()) printComponent(g, vScrollBar);
    }

    public void actionPerformed(ActionEvent event)
    {
        Component source = event.getSource();

        if (source == hScrollBar)
        {
            view.setLocation(insets[0] - hScrollBar.getValue(), view.getY());
            repaint();
        }
        else if (source == vScrollBar)
        {
            view.setLocation(view.getX(), insets[2] - vScrollBar.getValue());
            repaint();
        }
    }

    public boolean transferFocusDownCycle()
    {
        boolean b = super.transferFocusDownCycle();

        if (!b && (vScrollBar.getValue() < vScrollBar.getMaximum() - vScrollBar.getVisibleAmount()))
        {
            UIManager.postEvent(new MouseEvent(this, MouseEvent.MOUSE_SCROLL_VERTICAL, 0, 0, 5));
            return false;
        }

        return b;
    }

    public boolean transferFocusUpCycle()
    {
        boolean b = super.transferFocusUpCycle();

        if (!b && vScrollBar.getValue() > 0)
        {
            UIManager.postEvent(new MouseEvent(this, MouseEvent.MOUSE_SCROLL_VERTICAL, 0, 0, -5));
            return false;
        }

        return b;
    }

}
